/**********************************************************************

  Audacity: A Digital Audio Editor

  Wahwah

  Nasca Octavian Paul (Paul Nasca)

**********************************************************************/
#pragma once

#include "PerTrackEffect.h"
#include "ShuttleAutomation.h"

class EffectWahwahState
{
public:
    float samplerate;
    double depth;
    double freqofs;
    double phase;
    double outgain;
    double lfoskip;
    unsigned long skipcount;
    double xn1, xn2, yn1, yn2;
    double b0, b1, b2, a0, a1, a2;
};

struct EffectWahwahSettings
{
    /* Parameters:
    mFreq - LFO frequency
    mPhase - LFO startphase in RADIANS - useful for stereo WahWah
    mDepth - Wah depth
    mRes - Resonance
    mFreqOfs - Wah frequency offset
    mOutGain - output gain

    !!!!!!!!!!!!! IMPORTANT!!!!!!!!! :
    mDepth and mFreqOfs should be from 0(min) to 1(max) !
    mRes should be greater than 0 !  */

    static constexpr double freqDefault = 1.5;
    static constexpr double phaseDefault = 0.0;
    static constexpr int depthDefault = 70;
    static constexpr double resDefault = 2.5;
    static constexpr int freqOfsDefault = 30;
    static constexpr double outGainDefault = -6.0;

    double mFreq { freqDefault };
    double mPhase { phaseDefault };
    int mDepth { depthDefault };
    double mRes { resDefault };
    int mFreqOfs { freqOfsDefault };
    double mOutGain { outGainDefault };
};

class BUILTIN_EFFECTS_API WahWahBase : public EffectWithSettings<EffectWahwahSettings, PerTrackEffect>
{
public:
    static const ComponentInterfaceSymbol Symbol;

    WahWahBase();
    virtual ~WahWahBase();

    // ComponentInterface implementation

    ComponentInterfaceSymbol GetSymbol() const override;
    TranslatableString GetDescription() const override;
    ManualPageID ManualPage() const override;

    // EffectDefinitionInterface implementation

    EffectType GetType() const override;
    RealtimeSince RealtimeSupport() const override;

    // Effect implementation

    struct BUILTIN_EFFECTS_API Instance : public PerTrackEffect::Instance, public EffectInstanceWithBlockSize
    {
        explicit Instance(const PerTrackEffect& effect)
            : PerTrackEffect::Instance {effect}
        {
        }

        bool ProcessInitialize(
            EffectSettings& settings, double sampleRate, ChannelNames chanMap) override;

        size_t ProcessBlock(
            EffectSettings& settings, const float* const* inBlock, float* const* outBlock, size_t blockLen) override;

        // bool ProcessFinalize() noexcept override;

        bool RealtimeInitialize(EffectSettings& settings, double, size_t) override;

        bool RealtimeAddProcessor(
            EffectSettings& settings, EffectOutputs* pOutputs, unsigned numChannels, float sampleRate) override;

        bool RealtimeFinalize(EffectSettings& settings) noexcept override;

        size_t RealtimeProcess(
            size_t group, EffectSettings& settings, const float* const* inbuf, float* const* outbuf, size_t numSamples) override;

        void InstanceInit(
            EffectSettings& settings, EffectWahwahState& data, float sampleRate);

        size_t InstanceProcess(
            EffectSettings& settings, EffectWahwahState& data, const float* const* inBlock, float* const* outBlock, size_t blockLen);

        unsigned GetAudioInCount() const override;
        unsigned GetAudioOutCount() const override;

        EffectWahwahState mState;
        std::vector<WahWahBase::Instance> mSlaves;
    };

    std::shared_ptr<EffectInstance> MakeInstance() const override;

protected:
    // WahWahBase implementation

    const EffectParameterMethods& Parameters() const override;

    static constexpr EffectParameter Freq { &EffectWahwahSettings::mFreq,
                                            L"Freq",
                                            EffectWahwahSettings::freqDefault,
                                            0.1,
                                            4.0,
                                            10 };
    static constexpr EffectParameter Phase { &EffectWahwahSettings::mPhase,
                                             L"Phase",
                                             EffectWahwahSettings::phaseDefault,
                                             0.0,
                                             360.0,
                                             1 };
    static constexpr EffectParameter Depth {
        &EffectWahwahSettings::mDepth,
        L"Depth",
        EffectWahwahSettings::depthDefault,
        0,
        100,
        1
    }; // scaled to 0-1 before processing
    static constexpr EffectParameter Res { &EffectWahwahSettings::mRes,
                                           L"Resonance",
                                           EffectWahwahSettings::resDefault,
                                           0.1,
                                           10.0,
                                           10 };
    static constexpr EffectParameter FreqOfs {
        &EffectWahwahSettings::mFreqOfs,
        L"Offset",
        EffectWahwahSettings::freqOfsDefault,
        0,
        100,
        1
    }; // scaled to 0-1 before processing
    static constexpr EffectParameter OutGain {
        &EffectWahwahSettings::mOutGain,
        L"Gain",
        EffectWahwahSettings::outGainDefault,
        -30.0,
        30.0,
        1
    };
};
